{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "\"\"\"\n",
    "# BEGIN BINGO_DEMO\n",
    "\n",
    ">>> bingo = BingoCage(range(3))\n",
    ">>> bingo.pick()\n",
    "1\n",
    ">>> bingo()\n",
    "0\n",
    ">>> callable(bingo)\n",
    "True\n",
    "\n",
    "# END BINGO_DEMO\n",
    "\n",
    "\"\"\"\n",
    "\n",
    "# BEGIN BINGO\n",
    "\n",
    "import random\n",
    "\n",
    "class BingoCage:\n",
    "\n",
    "    def __init__(self, items):\n",
    "        self._items = list(items)  # <1>\n",
    "        random.shuffle(self._items)  # <2>\n",
    "\n",
    "    def pick(self):  # <3>\n",
    "        try:\n",
    "            return self._items.pop()\n",
    "        except IndexError:\n",
    "            raise LookupError('pick from empty BingoCage')  # <4>\n",
    "\n",
    "    def __call__(self):  # <5>\n",
    "        return self.pick()\n",
    "\n",
    "# END BINGO\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "\"\"\"\n",
    "    >>> clip('banana ', 6)\n",
    "    'banana'\n",
    "    >>> clip('banana ', 7)\n",
    "    'banana'\n",
    "    >>> clip('banana ', 5)\n",
    "    'banana'\n",
    "    >>> clip('banana split', 6)\n",
    "    'banana'\n",
    "    >>> clip('banana split', 7)\n",
    "    'banana'\n",
    "    >>> clip('banana split', 10)\n",
    "    'banana'\n",
    "    >>> clip('banana split', 11)\n",
    "    'banana'\n",
    "    >>> clip('banana split', 12)\n",
    "    'banana split'\n",
    "\"\"\"\n",
    "\n",
    "# BEGIN CLIP\n",
    "\n",
    "def clip(text, max_len=80):\n",
    "    \"\"\"Return text clipped at the last space before or after max_len\n",
    "    \"\"\"\n",
    "    end = None\n",
    "    if len(text) > max_len:\n",
    "        space_before = text.rfind(' ', 0, max_len)\n",
    "        if space_before >= 0:\n",
    "            end = space_before\n",
    "        else:\n",
    "            space_after = text.rfind(' ', max_len)\n",
    "            if space_after >= 0:\n",
    "                end = space_after\n",
    "    if end is None:  # no spaces were found\n",
    "        end = len(text)\n",
    "    return text[:end].rstrip()\n",
    "\n",
    "# END CLIP"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "\"\"\"\n",
    "    >>> clip('banana ', 6)\n",
    "    'banana'\n",
    "    >>> clip('banana ', 7)\n",
    "    'banana'\n",
    "    >>> clip('banana ', 5)\n",
    "    'banana'\n",
    "    >>> clip('banana split', 6)\n",
    "    'banana'\n",
    "    >>> clip('banana split', 7)\n",
    "    'banana'\n",
    "    >>> clip('banana split', 10)\n",
    "    'banana'\n",
    "    >>> clip('banana split', 11)\n",
    "    'banana'\n",
    "    >>> clip('banana split', 12)\n",
    "    'banana split'\n",
    "\"\"\"\n",
    "\n",
    "# BEGIN CLIP_ANNOT\n",
    "\n",
    "def clip(text:str, max_len:'int > 0'=80) -> str:  # <1>\n",
    "    \"\"\"Return text clipped at the last space before or after max_len\n",
    "    \"\"\"\n",
    "    end = None\n",
    "    if len(text) > max_len:\n",
    "        space_before = text.rfind(' ', 0, max_len)\n",
    "        if space_before >= 0:\n",
    "            end = space_before\n",
    "        else:\n",
    "            space_after = text.rfind(' ', max_len)\n",
    "            if space_after >= 0:\n",
    "                end = space_after\n",
    "    if end is None:  # no spaces were found\n",
    "        end = len(text)\n",
    "    return text[:end].rstrip()\n",
    "\n",
    "# END CLIP_ANNOT"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    ">>> from clip_annot import clip\n",
    ">>> from inspect import signature\n",
    ">>> sig = signature(clip)\n",
    ">>> sig.return_annotation\n",
    "<class 'str'>\n",
    ">>> for param in sig.parameters.values():\n",
    "...     note = repr(param.annotation).ljust(13)\n",
    "...     print(note, ':', param.name, '=', param.default)\n",
    "<class 'str'> : text = <class 'inspect._empty'>\n",
    "'int > 0'     : max_len = 80"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    ">>> from clip import clip\n",
    ">>> clip.__defaults__\n",
    "(80,)\n",
    ">>> clip.__code__  # doctest: +ELLIPSIS\n",
    "<code object clip at 0x...>\n",
    ">>> clip.__code__.co_varnames\n",
    "('text', 'max_len', 'end', 'space_before', 'space_after')\n",
    ">>> clip.__code__.co_argcount\n",
    "2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    ">>> from clip import clip\n",
    ">>> from inspect import signature\n",
    ">>> sig = signature(clip)\n",
    ">>> sig  # doctest: +ELLIPSIS\n",
    "<inspect.Signature object at 0x...>\n",
    ">>> str(sig)\n",
    "'(text, max_len=80)'\n",
    ">>> for name, param in sig.parameters.items():\n",
    "...     print(param.kind, ':', name, '=', param.default)\n",
    "...\n",
    "POSITIONAL_OR_KEYWORD : text = <class 'inspect._empty'>\n",
    "POSITIONAL_OR_KEYWORD : max_len = 80"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "\n",
    "\n",
    "\"\"\"\n",
    "# BEGIN TAG_DEMO\n",
    ">>> tag('br')  # <1>\n",
    "'<br />'\n",
    ">>> tag('p', 'hello')  # <2>\n",
    "'<p>hello</p>'\n",
    ">>> print(tag('p', 'hello', 'world'))\n",
    "<p>hello</p>\n",
    "<p>world</p>\n",
    ">>> tag('p', 'hello', id=33)  # <3>\n",
    "'<p id=\"33\">hello</p>'\n",
    ">>> print(tag('p', 'hello', 'world', cls='sidebar'))  # <4>\n",
    "<p class=\"sidebar\">hello</p>\n",
    "<p class=\"sidebar\">world</p>\n",
    ">>> tag(content='testing', name=\"img\")  # <5>\n",
    "'<img content=\"testing\" />'\n",
    ">>> my_tag = {'name': 'img', 'title': 'Sunset Boulevard',\n",
    "...           'src': 'sunset.jpg', 'cls': 'framed'}\n",
    ">>> tag(**my_tag)  # <6>\n",
    "'<img class=\"framed\" src=\"sunset.jpg\" title=\"Sunset Boulevard\" />'\n",
    "\n",
    "# END TAG_DEMO\n",
    "\"\"\"\n",
    "\n",
    "\n",
    "# BEGIN TAG_FUNC\n",
    "def tag(name, *content, cls=None, **attrs):\n",
    "    \"\"\"Generate one or more HTML tags\"\"\"\n",
    "    if cls is not None:\n",
    "        attrs['class'] = cls\n",
    "    if attrs:\n",
    "        attr_str = ''.join(' %s=\"%s\"' % (attr, value)\n",
    "                           for attr, value\n",
    "                           in sorted(attrs.items()))\n",
    "    else:\n",
    "        attr_str = ''\n",
    "    if content:\n",
    "        return '\\n'.join('<%s%s>%s</%s>' %\n",
    "                         (name, attr_str, c, name) for c in content)\n",
    "    else:\n",
    "        return '<%s%s />' % (name, attr_str)\n",
    "# END TAG_FUNC"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.0a1"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 0
}
